/*
    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/


/**
 * \file c_parser.h
 * \brief  Expression parser
 * \author Jos de Jong
 * \date 2007-12-22
 */


#ifndef msPARSER_H
#define msPARSER_H
#include <msScalarFunction.h>
#include <muParser.h>

namespace atomism
{


class msParser : public msScalarFunction
{
      //!\name from msRegister 
      //@{
      static msRegistrar Registrar;
      static bool  isParserRegisteredInPython;
      static msRegister* createInstance() { return new msParser; }
      //@}   
      
      
protected:
  
      void registryInPython();
 
      msParser() : msScalarFunction(){
	     constructVar("msParser","Parser","parser");
	     }    
   
public:
        
       enum TOKENTYPE {NOTHING = -1, DELIMETER, NUMBER, VARIABLE, FUNCTION, UNKNOWN};
	
       static boost::shared_ptr<msParser> New( string unitexpr ){
	    
	       boost::shared_ptr<msParser> T( new msParser );
	       LOGGER_ENTER_FUNCTION_DBG("msParser::New(boost::shared_ptr<msUnitsManager> unit)",T->getFullId());
	       T->initialize(); 
	       T->getYUnit().set(unitexpr);
	       T->update();
	       LOGGER_EXIT_FUNCTION();
	       return T;
	       }
    
	virtual boost::shared_ptr<msTreeMapper> clone() { 
            boost::shared_ptr<msParser> clone = New(""); 
	    clone->msTreeMapper::operator=(*this);					      
	    return clone;
            }  
    
    
    virtual void initialize()  {
        msScalarFunction::initialize();
        declareAttribute(Expression,"Expression");
    };
    
    virtual void update(){
        
        LOGGER_ENTER_FUNCTION_DBG("void msParser::update()",getFullId());
        msScalarFunction::update();
        setVariables();
        setExpression(Expression);
        LOGGER_EXIT_FUNCTION();
    }
    
	boost::shared_ptr<msTreeMapper> setExpression(std::string exp){
        
	    Expression=exp;
        Parser.SetExpr(Expression);
        return mySharedPtr();
    }

	boost::shared_ptr<msTreeMapper> setVariables(){
	   
        for( size_t i=0 ; i<getCoordinates()->noOfDim() ; ++i ){
            string id=(*getCoordinates())[i]->getId();
            double* value = &(*getCoordinates())[i]->Value;
            try{
                Parser.DefineVar(id,value );
            }
            catch( mu::Parser::exception_type &e){
                stringstream out;
                out<<"Error in the parser variable definition.\n"<<e.GetMsg()<<endl;
                msError e2(out.str(), "double msParser::setVariables()", getFullId());
                
                BOOST_THROW_EXCEPTION(e2);
                }

        }
         
	      std::map< std::string , double >::iterator it = Constants.begin();

              for(; it!=Constants.end() ; ++it ) Parser.DefineVar( (*it).first , &((*it).second) );
	      return mySharedPtr();
	      }
	      
	std::string getExpression() const {return Expression;}   
	
	double evaluate();
	
		      
	std::ostream& print(std::ostream& out) const;
      
      	std::string getLabel(){return ("Id: "+getId()+"; expression: "+Expression);}
    
 private:
    
    double value;
    mu::Parser Parser;
	std::string Expression;
	
};

}
#endif // msPARSER_H






